package com.talkyun.openx;

import com.talkyun.openx.error.ExceptionHandler;
import com.talkyun.openx.server.AbstractBaseFilter;
import com.talkyun.openx.server.ServletHandler;
import com.talkyun.openx.server.ServletStatus;
import com.talkyun.openx.server.core.ServiceResponse;
import com.talkyun.openx.server.error.PageBuilder;
import com.talkyun.openx.server.helper.VersionHelper;
import com.talkyun.openx.server.session.SessionCleaner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.talkyun.openx.server.core.ServiceResponse.Status.ERROR;
import static com.talkyun.openx.server.helper.IconHelper.getFavIconBuffer;
import static java.util.concurrent.TimeUnit.DAYS;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;

public class RestfulFilter extends AbstractBaseFilter {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    private String version = VersionHelper.getOpenxVersion();

    private ServletStatus status;
    private ServletHandler handler;
    private ExceptionHandler killer;

    private String[] excludePath;
    // private RearGuardTimer guardTimer;
    private SessionCleaner sessionCleaner;

    private PageBuilder pageBuilder = PageBuilder.get();
    // private SessionManager sessionManager = SessionManager.get();

    @Override
    public void init(FilterConfig fc) throws ServletException {
        super.init(fc);

        status = new ServletStatus(fc.getServletContext());
        handler = new ServletHandler(fc.getServletContext());
        killer = new ExceptionHandler();

        // init exclude path array
        String uri = getInitParameter(fc, "excludeURI", "openxExcludeURI");
        if (isBlank(uri)) {
            excludePath = new String[0];
        } else {
            excludePath = uri.trim().split(",");
            for (int i = 0; i < excludePath.length; i++) {
                excludePath[i] = excludePath[i].trim().toLowerCase();
            }
        }
        logger.info("-> openx {} is ready.", version);
        System.out.println("-------------------------------------------------------------------------------\n");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc) {
        try {
            doMyFilter(req, resp, fc);
        } catch (Throwable t) {
            String message = killer.encode(t);
            this.doWrite(SC_INTERNAL_SERVER_ERROR, message, (HttpServletResponse) resp);
        }
    }

    private void doMyFilter(ServletRequest req, ServletResponse resp, FilterChain fc) throws IOException, ServletException {
        String uri = ((HttpServletRequest) req).getRequestURI().toLowerCase();
        String method = ((HttpServletRequest) req).getMethod().toLowerCase();

        // First favicon.ico
        if ("/favicon.ico".equals(uri)) {
            byte[] buf = getFavIconBuffer("/webapp/favicon.ico");
            HttpServletResponse response = (HttpServletResponse) resp;
            response.setHeader("Cache-Control", "max-age=86400");
            long expires = System.currentTimeMillis() + DAYS.toMillis(1);
            response.setDateHeader("Expires", expires);
            response.setContentType("image/x-icon");
            response.getOutputStream().write(buf);
            return;
        }

        // Monitor: HEAD / HTTP/1.0
        if ("head".equals(method) && "/".equals(uri)) {
            resp.getWriter().println("OK");
            return;
        }

        // Static resource or exclude uri
        if (this.isStaticResource(uri) || this.isExcludeURI(uri)) {
            fc.doFilter(req, resp);
            return;
        }

        // status
        if ("/status".equalsIgnoreCase(uri.trim())) {
            String fmt = ((HttpServletRequest) req).getQueryString();
            String status = this.status.getStatus(fmt);
            super.doWrite(SC_OK, status, (HttpServletResponse) resp);
            return;
        }

        if ("get".equals(method) || "post".equals(method) || "options".equals(method)) {
            // sessionManager.updateActiveTime(((HttpServletRequest) req).getSession().getId());
            // now to handle request
            handler.handle((HttpServletRequest) req, (HttpServletResponse) resp);
        } else {
            // put,delete ...
            fc.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {
        // guardTimer.shutdown();
    }

    @Override
    protected void handle(HttpServletRequest req, HttpServletResponse resp, FilterChain fc) throws IOException, ServletException {

    }

    private boolean isStaticResource(String uri) {
        String[] ss = {"/", ".ico", ".js", ".css", ".jpg", ".png", ".gif", ".htm", ".html", ".xml", ".json", ".txt", ".ttf", ".svg", ".woff", ".woff2", ".eot"};
        for (String s : ss) {
            if (uri.endsWith(s)) {
                return true;
            }
        }
        return false;
    }

    //    private boolean isExcludeURI(String uri) {
    //        for (String exclude : excludePath) {
    //            if (uri.startsWith(exclude)) {
    //                return true;
    //            }
    //        }
    //        return false;
    //    }
    //
    //    protected String getInitParameter(FilterConfig fc, String servletParamName, String contextParamName) {
    //        String param = fc.getInitParameter(servletParamName);
    //        if (isBlank(param)) {
    //            param = fc.getServletContext().getInitParameter(contextParamName);
    //        }
    //        return isBlank(param) ? null : param.trim();
    //    }
    //
    //    protected boolean isBlank(String s) {
    //        return s == null || s.trim().length() == 0;
    //    }
}